//*******************************************************************
// Simple dialog-based application that demonstrates Windows Vista menu 
// features.
//
// Draw a sample owner-draw menu using Windows XP-style rendering and // Windows Vista-style rendering.
//*********************************************************************
#include "stdafx.h"
#include "menumetrics.h"
#include "owner_draw_menu.h"
                                // you use IDList. 

HRESULT CClassicOwnerDrawMenu::Initialize(HWND hwndParent)
{
	_hwndParent = hwndParent;
	return S_OK;
}

void CClassicOwnerDrawMenu::MeasureItem(__in MENUITEM *pmi, __inout MEASUREITEMSTRUCT *pmis)
{
	if (pmi->mii.fType & MFT_SEPARATOR)
	{
		pmis->itemWidth = 1; 
		pmis->itemHeight = _cyMenuMargin * 2 + _cySeparator;
	}
	else
	{
		HDC hdc = GetDC(_hwndParent);
		if (hdc)
		{
			SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
			SIZE size = {0};
			size_t cch = 0;
			StringCchLength(pmi->szItemText, ARRAYSIZE(
				pmi->szItemText), &cch);
			GetTextExtentPoint32(hdc, pmi->szItemText,  
				static_cast<ULONG>(cch), &size);
			pmis->itemWidth = size.cx + 2 * _cxMenuMargin + 
				_cxCheckmark + _cxGutter;
			pmis->itemHeight = max(size.cy, _cyCheckmark) + 
				_cyMenuMargin * 2;

			ReleaseDC(_hwndParent, hdc);
		}
	}
}

void CClassicOwnerDrawMenu::DrawItem(__in MENUITEM *pmi, __in 
									 DRAWITEMSTRUCT *pdis)
{
	_InitMenuDC(pmi, pdis);
	switch (pdis->itemAction)
	{
	case ODA_DRAWENTIRE:
	case ODA_SELECT:
		_DrawMenuItem(pmi, pdis);
		break;

	case ODA_FOCUS:
		break;
	}
}

void CClassicOwnerDrawMenu::SelectedItem(int id)
{
	_idLastSelected = id;
}

HRESULT CClassicOwnerDrawMenu::SettingChange()
{

	return S_OK;
}

void CClassicOwnerDrawMenu::Release()
{
	delete this;
}

void CClassicOwnerDrawMenu::_DrawMenuItem(__in MENUITEM *pmi, __in  
										  DRAWITEMSTRUCT *pdis)
{
	if (pmi->mii.fType & MFT_SEPARATOR)
	{
		PatBlt(pdis->hDC, pdis->rcItem.left + _cxMenuMargin, 
			pdis->rcItem.top + _cyMenuMargin + 1,
			RectWidth(pdis->rcItem) - 2 * _cxMenuMargin,
			_cySeparator,
			BLACKNESS);
	}
	else
	{
		// Start rect out to be rcItem minus the margins.
		RECT rc = pdis->rcItem;
		InflateRect(&rc, -_cxMenuMargin, -_cyMenuMargin);
		ExtTextOut(pdis->hDC, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 
			0, NULL);

		// Draw the checkbox if necessary.
		if (pmi->mii.fState & MFS_CHECKED)
		{
			RECT rcCheck;
			rcCheck.left = rc.left;
			rcCheck.right = rc.left + _cxCheckmark;
			rcCheck.top = rc.top + (RectHeight(rc) - _cyCheckmark + 1)
				/ 2;
			rcCheck.bottom = rc.top + _cyCheckmark;
			PatBlt(pdis->hDC, rcCheck.left, rcCheck.top,
				RectWidth(rcCheck), RectHeight(rcCheck),
				BLACKNESS);
		}
		rc.left += _cxCheckmark;

		// Draw the gutter divider.
		PatBlt(pdis->hDC, rc.left + _cxGutterMargin, rc.top, 
			_cxGutterLine, RectHeight(pdis->rcItem), BLACKNESS);
		rc.left += _cxGutter;

		// Draw the text.
		DrawText(pdis->hDC, pmi->mii.dwTypeData, pmi->mii.cch, &rc, 
			DT_VCENTER | DT_SINGLELINE);
	}
}

void CClassicOwnerDrawMenu::_InitMenuDC(__in MENUITEM *pmi, __in DRAWITEMSTRUCT *pdis)
{
	if (pmi->mii.fState & MFS_GRAYED)
	{
		SetTextColor(pdis->hDC, GetSysColor(COLOR_GRAYTEXT));
		SetBkColor(pdis->hDC, GetSysColor(COLOR_MENU));
	}
	else if (pdis->itemState & ODS_SELECTED)
	{
		SetTextColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
		SetBkColor(pdis->hDC, GetSysColor(COLOR_HIGHLIGHT));
	}
	else if (pmi->mii.wID == _idLastSelected)
	{
		SetTextColor(pdis->hDC, GetSysColor(COLOR_MENUTEXT));
		SetBkColor(pdis->hDC, _rgbPreviousSelection);
	}
	else
	{
		SetTextColor(pdis->hDC, GetSysColor(COLOR_MENUTEXT));
		SetBkColor(pdis->hDC, GetSysColor(COLOR_MENU));
	}
}

//
// ResetMenuMetrics: Menus cache their widths so you have to clear the 
// cache when switching between owner-draw methods. This can be 
// achieved by calling SetMenuItemInfo() with the MIIM_BITMAP flag set // in fMask.
//
void ResetMenuMetrics(HMENU hmenu)
{
	for (int i = GetMenuItemCount(hmenu); i > 0; --i)
	{
		MENUITEMINFO mii = { sizeof(mii) };
		mii.fMask = MIIM_BITMAP;
		if (GetMenuItemInfo(hmenu, i-1, TRUE, &mii))
		{
			SetMenuItemInfo(hmenu, i-1, TRUE, &mii);
		}
	}
}



void CVistaOwnerDrawMenu::_DrawMenuItem( __in MENUITEM *pmi, __in DRAWITEMSTRUCT *pdis )
{
	POPUPITEMSTATES iStateId = _pMetrics->ToItemStateId(pdis->itemState);

	DRAWITEMMETRICS dim;
	_pMetrics->LayoutMenuItem(pmi, pdis, &dim);

	if (IsThemeBackgroundPartiallyTransparent(_pMetrics->hTheme, 
		MENU_POPUPITEM, iStateId))
	{
		DrawThemeBackground(_pMetrics->hTheme, pdis->hDC, 
			MENU_POPUPBACKGROUND, 0, &pdis->rcItem, 
			NULL);
	}

	DrawThemeBackground(_pMetrics->hTheme,
		pdis->hDC,
		MENU_POPUPGUTTER,
		0,
		&dim.rcGutter,
		NULL);             

	if (pmi->mii.fType & MFT_SEPARATOR)
	{
		DrawThemeBackground(_pMetrics->hTheme, pdis->hDC, 
			MENU_POPUPSEPARATOR, 0, 
			&dim.rgrc[POPUP_SEPARATOR], NULL);             
	}
	else
	{
		// Draw last selected item.
		if (pmi->mii.wID == _idLastSelected)
		{
			RECT rc = dim.rcSelection;
			SetBkColor(pdis->hDC, _rgbPreviousSelection);
			ExtTextOut(pdis->hDC, rc.left, rc.top, ETO_OPAQUE, &rc, 
				NULL, 0, NULL);
		}

		// Item selection
		DrawThemeBackground(_pMetrics->hTheme, pdis->hDC, 
			MENU_POPUPITEM, iStateId, &dim.rcSelection, 
			NULL);

		// Draw the checkbox if necessary.
		if (pmi->mii.fState & MFS_CHECKED)
		{
			DrawThemeBackground(_pMetrics->hTheme,
				pdis->hDC,
				MENU_POPUPCHECKBACKGROUND, 
				_pMetrics->ToCheckBackgroundStateId(iStateId),
				&dim.rcCheckBackground,
				NULL);

			DrawThemeBackground(_pMetrics->hTheme,
				pdis->hDC,
				MENU_POPUPCHECK, 
				_pMetrics->ToCheckStateId(pmi->mii.fType, iStateId),
				&dim.rgrc[POPUP_CHECK],
				NULL);
		}

		// Draw the text.
		ULONG uAccel = ((pdis->itemState & ODS_NOACCEL) ? DT_HIDEPREFIX : 0);
		DrawThemeText(_pMetrics->hTheme,
			pdis->hDC,
			MENU_POPUPITEM,
			iStateId,
			pmi->mii.dwTypeData, 
			pmi->mii.cch,
			DT_SINGLELINE | DT_LEFT | uAccel,
			0,
			&dim.rgrc[POPUP_TEXT]);

	}
}

CVistaOwnerDrawMenu::CVistaOwnerDrawMenu() :
	_idLastSelected(-1),
	_pMetrics(NULL)
{

}

CVistaOwnerDrawMenu::~CVistaOwnerDrawMenu()
{
	delete _pMetrics;
}

HRESULT CVistaOwnerDrawMenu::Initialize(HWND hwndParent)
{
	_hwndParent = hwndParent;
	return CMenuMetrics::EnsureInitialized(_hwndParent, &_pMetrics);
}

void CVistaOwnerDrawMenu::MeasureItem(__in MENUITEM *pmi, __inout 
									  MEASUREITEMSTRUCT *pmis)
{
	_pMetrics->MeasureMenuItem(pmi, pmis);
}

void CVistaOwnerDrawMenu::DrawItem(__in MENUITEM *pmi, __in 
								   DRAWITEMSTRUCT *pdis)
{
	switch (pdis->itemAction)
	{
	case ODA_DRAWENTIRE:
	case ODA_SELECT:
		_DrawMenuItem(pmi, pdis);
		break;

	case ODA_FOCUS:
		break;
	}
}

void CVistaOwnerDrawMenu::SelectedItem(int id)
{
	_idLastSelected = id;
}

HRESULT CVistaOwnerDrawMenu::SettingChange()
{
	// Regenerate theme handle to synchronize with new settings
	_pMetrics->Flush();
	return CMenuMetrics::EnsureInitialized(_hwndParent, &_pMetrics);
}

void CVistaOwnerDrawMenu::Release()
{
	delete this;
}